001    /*
002     * Copyright 2005 Stephen J. McConnell
003     *
004     * Licensed  under the  Apache License,  Version 2.0  (the "License");
005     * you may not use  this file  except in  compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     *   http://www.apache.org/licenses/LICENSE-2.0
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed  under the  License is distributed on an "AS IS" BASIS,
012     * WITHOUT  WARRANTIES OR CONDITIONS  OF ANY KIND, either  express  or
013     * implied.
014     *
015     * See the License for the specific language governing permissions and
016     * limitations under the License.
017     */
018    
019    package net.dpml.library.info;
020    
021    import java.util.Arrays;
022    import java.util.ArrayList;
023    import java.util.Properties;
024    
025    import net.dpml.lang.Enum;
026    
027    import net.dpml.transit.Artifact;
028    
029    /**
030     * The ResourceDirective class describes an available resource.
031     *
032     * @author <a href="http://www.dpml.net">Digital Product Meta Library</a>
033     * @version 1.1.0
034     */
035    public class ResourceDirective extends AbstractDirective
036    {
037       /**
038        * External resource constant identifier.
039        */
040        public static final Classifier EXTERNAL = Classifier.EXTERNAL;
041        
042       /**
043        * Local resource constant identifier.
044        */
045        public static final Classifier LOCAL = Classifier.LOCAL;
046         
047       /**
048        * Anonymous resource constant identifier.
049        */
050        public static final Classifier ANONYMOUS = Classifier.ANONYMOUS;
051        
052        private final String m_scheme;
053        private final String m_name;
054        private final String m_version;
055        private final String m_basedir;
056        private final TypeDirective[] m_types;
057        private final DataDirective[] m_data;
058        private final DependencyDirective[] m_dependencies;
059        private final Classifier m_classifier;
060        private final FilterDirective[] m_filters;
061        private final InfoDirective m_info;
062        
063       /**
064        * Creation of a new anonymous resource directive.
065        * @param scheme the schema name
066        * @param name the resource name
067        * @param version the resource version
068        * @param type the resource type
069        * @param properties suppliementary properties
070        * @return the resource directive
071        */
072        public static ResourceDirective createAnonymousResource( 
073          String scheme, String name, String version, String type, Properties properties )
074        {
075            return new ResourceDirective( scheme, name, type, version, properties );
076        }
077    
078       /**
079        * Creation of a new resource directive.  If the resource name if composite
080        * then the resource directive will be a module directive instance that either 
081        * encloses the resource or enclosed a resource containing the resource.
082        *
083        * @param name the resource name
084        * @param version the resource version
085        * @param classifier LOCAL or EXTERNAL classifier
086        * @param basedir the project basedir
087        * @param info info descriptor
088        * @param data types produced by the resource
089        * @param dependencies resource dependencies
090        * @param properties suppliementary properties
091        * @param filters project filters
092        * @return the immediate enclosing resource
093        */
094        public static ResourceDirective createResourceDirective( 
095          String name, String version, Classifier classifier, String basedir, 
096          InfoDirective info, DataDirective[] data, 
097          DependencyDirective[] dependencies, Properties properties, 
098          FilterDirective[] filters )
099        {
100            int n = name.indexOf( "/" );
101            if( n > -1 )
102            {
103                ResourceDirective resource = null;
104                String[] elements = name.split( "/", -1 );
105                for( int i = ( elements.length-1 ); i>-1; i-- )
106                {
107                    String elem = elements[i];
108                    if( i == ( elements.length-1 ) )
109                    {
110                        resource =  
111                          new ResourceDirective(
112                            elem, version, classifier, basedir, info, data, dependencies,
113                            properties, filters );
114                    }
115                    else
116                    {
117                        resource = 
118                          new ModuleDirective(
119                            elem, null, Classifier.EXTERNAL, null, null,
120                            new DataDirective[0], new DependencyDirective[0],
121                            new ResourceDirective[]{resource}, null, null );
122                    }
123                }
124                return resource;
125            }
126            else
127            {
128                return new ResourceDirective(
129                  name, version, classifier, basedir, info, data, 
130                  dependencies, properties, filters );
131            }
132        }
133    
134       /**
135        * Creation of a new annonomous resource directive.
136        * @param scheme the resource schema (artifact or link)
137        * @param name the resource name
138        * @param version the resource version
139        * @param properties suppliementary properties
140        */
141        private ResourceDirective( 
142          String scheme, String name, String type, String version, Properties properties )
143        {
144            super( properties );
145            
146            if( null == name )
147            {
148                throw new NullPointerException( "name" );
149            }
150            
151            m_name = name;
152            m_types = new TypeDirective[]{new TypeDirective( type )};
153            m_data = m_types;
154            m_dependencies = new DependencyDirective[0];
155            m_classifier = Classifier.ANONYMOUS;
156            m_version = version;
157            m_basedir = ".";
158            m_info = new InfoDirective( null, null );
159            m_filters = new FilterDirective[0];
160            m_scheme = scheme;
161        }
162        
163       /**
164        * Creation of a new resource directive.
165        * @param name the resource name
166        * @param version the resource version
167        * @param classifier LOCAL or EXTERNAL classifier
168        * @param basedir the project basedir
169        * @param info info descriptor
170        * @param data type production data
171        * @param dependencies resource dependencies
172        * @param properties suppliementary properties
173        * @param filters suppliementary filters
174        */
175        ResourceDirective( 
176          String name, String version, Classifier classifier, String basedir, 
177          InfoDirective info, DataDirective[] data, 
178          DependencyDirective[] dependencies, Properties properties, 
179          FilterDirective[] filters )
180        {
181            super( properties );
182            
183            if( null == name )
184            {
185                throw new NullPointerException( "name" );
186            }
187            if( null == data )
188            {
189                throw new NullPointerException( "data" );
190            }
191            if( null == dependencies )
192            {
193                throw new NullPointerException( "dependencies" );
194            }
195            if( null == classifier )
196            {
197                throw new NullPointerException( "classifier" );
198            }
199            
200            m_name = name;
201            m_version = version;
202            m_basedir = basedir;
203            m_classifier = classifier;
204            m_scheme = Artifact.ARTIFACT;
205            
206            if( null == info )
207            {
208                m_info = new InfoDirective( null, null );
209            }
210            else
211            {
212                m_info = info;
213            }
214            
215            m_dependencies = dependencies;
216            
217            if( null == filters )
218            {
219                m_filters = new FilterDirective[0];
220            }
221            else
222            {
223                m_filters = filters;
224            }
225            
226            ArrayList list = new ArrayList();
227            for( int i=0; i<data.length; i++ )
228            {
229                DataDirective directive = data[i];
230                if( directive instanceof TypeDirective )
231                {
232                    list.add( directive );
233                }
234            }
235            m_types = (TypeDirective[]) list.toArray( new TypeDirective[0] );
236            m_data = data;
237        }
238        
239       /**
240        * Return the resource name.
241        * @return the name
242        */
243        public String getName()
244        {
245            return m_name;
246        }
247        
248       /**
249        * Return the resource version.
250        * @return the version
251        */
252        public String getVersion()
253        {
254            return m_version;
255        }
256        
257       /**
258        * Return the resource basedir.
259        * @return the basedir
260        */
261        public String getBasedir()
262        {
263            return m_basedir;
264        }
265        
266       /**
267        * Return the info descriptor.
268        * @return the info descriptor
269        */
270        public InfoDirective getInfoDirective()
271        {
272            return m_info;
273        }
274        
275       /**
276        * Return the resource classifier.
277        * @return the classifier (LOCAL, EXTERNAL or ANONYMOUS)
278        */
279        public Classifier getClassifier()
280        {
281            return m_classifier;
282        }
283        
284       /**
285        * Return true if this represents a local project.
286        * @return true if local
287        */
288        public boolean isLocal()
289        {
290            return LOCAL.equals( m_classifier );
291        }
292        
293       /**
294        * Return true if this represents a anonymous resource.
295        * @return true if anonymous
296        */
297        public boolean isAnonymous()
298        {
299            return ANONYMOUS.equals( m_classifier );
300        }
301        
302       /**
303        * Return the scheme to use when declaring the published artifact (used
304        * in conjunction with anonymous resources.
305        * @return the scheme
306        */
307        public String getScheme()
308        {
309            return m_scheme;
310        }
311        
312       /**
313        * Return an array of types representing artifacts associated
314        * with the resource.
315        * @return the type directives
316        */
317        public TypeDirective[] getTypeDirectives()
318        {
319            return m_types;
320        }
321        
322       /**
323        * Return an array of supplimentary filter directives.
324        * @return the filter directives
325        */
326        public FilterDirective[] getFilterDirectives()
327        {
328            return m_filters;
329        }
330        
331       /**
332        * Return an array of supporting production data directives
333        * (including all produced types).
334        * @return the data directives
335        */
336        public DataDirective[] getDataDirectives()
337        {
338            return m_data;
339        }
340        
341       /**
342        * Return an named type.
343        * @param name the type name
344        * @return the type directives
345        * @exception TypeUnknownException if the type name if not recornized within
346        *   the scope of the resource
347        */
348        public TypeDirective getTypeDirective( String name ) throws TypeUnknownException
349        {
350            for( int i=0; i<m_types.length; i++ )
351            {
352                TypeDirective type = m_types[i];
353                if( name.equals( type.getID() ) )
354                {
355                    return type;
356                }
357            }
358            throw new TypeUnknownException( name );
359        }
360            
361       /**
362        * Return an array of dependency directives.
363        * @return the dependency directive array
364        */
365        public DependencyDirective[] getDependencyDirectives()
366        {
367            return m_dependencies;
368        }
369        
370       /**
371        * Return an dependency directive matching a supplied scope.
372        * @param scope the scope
373        * @return the dependency directive matching the supplied scope
374        */
375        public DependencyDirective getDependencyDirective( Scope scope )
376        {
377            for( int i=0; i<m_dependencies.length; i++ )
378            {
379                DependencyDirective directive = m_dependencies[i];
380                if( scope.equals( directive.getScope() ) )
381                {
382                    return directive;
383                }
384            }
385            return new DependencyDirective( scope, new IncludeDirective[0] );
386        }
387        
388       /**
389        * Compare this object with another for equality.
390        * @param other the other object
391        * @return true if equal
392        */
393        public boolean equals( Object other )
394        {
395            if( super.equals( other ) && ( other instanceof ResourceDirective ) )
396            {
397                ResourceDirective object = (ResourceDirective) other;
398                if( !equals( m_name, object.m_name ) )
399                {
400                    return false;
401                }
402                else if( !equals( m_scheme, object.m_scheme ) )
403                {
404                    return false;
405                }
406                else if( !equals( m_version, object.m_version ) )
407                {
408                    return false;
409                }
410                else if( !equals( m_basedir, object.m_basedir ) )
411                {
412                    return false;
413                }
414                else if( !equals( m_info, object.m_info ) )
415                {
416                    return false;
417                }
418                else if( !Arrays.equals( m_data, object.m_data ) )
419                {
420                    return false;
421                }
422                else
423                {
424                    return Arrays.equals( m_dependencies, object.m_dependencies );
425                }
426            }
427            else
428            {
429                return false;
430            }
431        }
432        
433       /**
434        * Compute the hash value.
435        * @return the hashcode value
436        */
437        public int hashCode()
438        {
439            int hash = super.hashCode();
440            hash ^= super.hashValue( m_name );
441            hash ^= super.hashValue( m_scheme );
442            hash ^= super.hashValue( m_version );
443            hash ^= super.hashValue( m_basedir );
444            hash ^= super.hashValue( m_info );
445            hash ^= super.hashArray( m_data );
446            hash ^= super.hashArray( m_dependencies );
447            hash ^= super.hashArray( m_filters );
448            return hash;
449        }
450    
451       /**
452        * Resource classifier enumeration.
453        * @author <a href="mailto:dev-dpml@lists.ibiblio.org">The Digital Product Meta Library</a>
454        */
455        public static final class Classifier extends Enum
456        {
457            static final long serialVersionUID = 1L;
458    
459            /**
460            * Anonymous resources.
461            */
462            public static final Classifier ANONYMOUS = new Classifier( "anonymous" );
463            
464            /**
465            * External resource.
466            */
467            public static final Classifier EXTERNAL = new Classifier( "external" );
468    
469            /**
470            * Local resources.
471            */
472            public static final Classifier LOCAL = new Classifier( "local" );
473        
474           /**
475            * Internal constructor.
476            * @param label the enumeration label.
477            */
478            private Classifier( String label )
479            {
480                super( label );
481            }
482        
483           /**
484            * Create a classified matching the supplied name.
485            * @param value the classifier name
486            * @return the classifier
487            * @exception IllegalArgumentException if the supplied value is not recognized
488            */
489            public static Classifier parse( String value ) throws IllegalArgumentException
490            {
491                if( value.equalsIgnoreCase( "external" ) )
492                {
493                    return EXTERNAL;
494                }
495                else if( value.equalsIgnoreCase( "local" ) )
496                {
497                    return LOCAL;
498                }
499                else if( value.equalsIgnoreCase( "anonymous" ) )
500                {
501                    return ANONYMOUS;
502                }
503                else
504                {
505                    final String error =
506                      "Unrecognized module classifier argument [" + value + "]";
507                    throw new IllegalArgumentException( error );
508                }
509            }
510        }
511    }